home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2888 / 2888.xpi / content / sidebar.js < prev    next >
Text File  |  2009-12-17  |  53KB  |  1,619 lines

  1. var searchBox;
  2. var lastKeyPress=0;
  3.  
  4. var treeView;
  5. var lblsTreeView;
  6. //Vars for editable organize window
  7. var editField;
  8. var editRow;
  9. var editCol;
  10. var editOriginalValue;
  11. var cellOffset;
  12. //------
  13. var keyEvent;
  14. /*
  15.  * type=labels or details if its a tree in the organize window(double tree)
  16.  * type=complete if its in the sidebar(single tree)
  17.  * parent is the parent label, generally used on the details type when a label is clicked
  18.  */
  19. function GMarksTreeView(type,parent){
  20.   this.type=type;
  21.   if (parent && parent.length>0){
  22.     this.parentLbl=parent;
  23.     this.data=getTreeData(parent,true,type);
  24.   }
  25.   else
  26.     this.data=getVisibleData(type,this);
  27.   if (type=="complete"){
  28.     this.restoreContainers();
  29.   }
  30. }
  31. GMarksTreeView.prototype = {
  32.   rowsOpen: 0,
  33.   lastOpened: -1,
  34.   loading: false,
  35.   //column, order
  36.   sortinfo: ["name",0],
  37.   parentLbl: null,
  38.   treeBox: null,
  39.   selection: null,
  40.   get selectedData(){
  41.     var selected=new Array();
  42.     var start = {}, end = {};
  43.     var numRanges = this.selection.getRangeCount();
  44.     for (var t = 0; t < numRanges; t++){
  45.       this.selection.getRangeAt(t,start,end);
  46.       for (var idx = start.value; idx <= end.value; idx++){
  47.         //var item=dragSource.data[idx];
  48.         /* Check if parent is already selected */
  49.         var pIdx=idx,addItem=!this.isSeparator(pIdx);
  50.         while(pIdx>-1 && addItem){
  51.          pIdx = this.getParentIndex(pIdx);
  52.          if (pIdx>-1){
  53.           if (selected.indexOf(this.data[pIdx])>-1){
  54.             pIdx=-1;
  55.             addItem=false;
  56.           }
  57.          }
  58.         }
  59.         if (addItem)
  60.           selected.push(idx);
  61.       }
  62.     }
  63.     return selected;
  64.   },
  65.   editRow: -1,
  66.   editCol: -1,
  67.   editOriginalValue: -1,
  68.   editCell: {row: -1, col: null},
  69.   extras: 0,/*the count of Most Used, Most Recent, separators, etc */
  70.  
  71.   setTree: function(treeBox)         {
  72.     //dump("setTree: "+treeBox+"|"+this.treeBox+"\n")
  73.     //if (treeBox == null && this.treeBox != null){
  74.     //  this.lastRow = this.treeBox.getLastVisibleRow();
  75.     //  dump("set tree close last row: "+this.lastRow+"\n");
  76.     //} else if (this.treeBox == null && treeBox != null){
  77.     //  lastRow = treeBox.getLastVisibleRow();
  78.     //  dump("set tree open last row: "+lastRow+"|"+this.lastRow+"\n");
  79.     //  if (this.lastRow && this.lastRow > lastRow)
  80.     //    treeBox.scrollByLines(this.lastRow - lastRow);
  81.     //}
  82.     this.treeBox = treeBox;
  83.   },
  84.   getTreeBox: function()             { return this.treeBox; },
  85.   getTree: function()                { return this.treeBox?this.treeBox.treeBody.parentNode:null;},
  86.   isEditingCell: function(row,column){
  87.     var editing=false;
  88.     var tree=this.getTree();
  89.     /* FF3 Editing */
  90.     if (tree != null)
  91.       editing=tree.inputField!=null && tree.inputField.hidden==false;
  92.     if (editing && this.editCell.row==-1 && this.editCell.col==null){
  93.       this.editCell.row=row; this.editCell.col=column;
  94.     }
  95.     else if (this.editCell.row!=row || this.editCell.col!=column)
  96.       editing=false;
  97.     /* FF2 version - editing */
  98.     if (!editing && editField)
  99.       editing=(editField!=null && !editField.hidden) && row==editRow && column==editCol;
  100.     return editing;
  101.   },
  102.   getCellText: function(idx, column) {
  103.     var editing=this.isEditingCell(idx,column);
  104.     if (editing && !editField.hidden){
  105.     if ((this.getTree() && this.getTree().getAttribute("editing")=="true") || !this.data[idx])
  106.       return "";
  107.     }
  108.     switch (column.id){
  109.       case "mainCol":
  110.       case "nameCol":
  111.         var title=this.data[idx].title;
  112.         //Total Bookmarks+Labels in the current label
  113.         //not including sub-bookmarks & labels
  114.  
  115.       if (GMS.showCount && this.isContainer(idx) &&
  116.           this.data[idx].data.length>0){
  117.           if (!editing)
  118.           title+=' ('+this.data[idx].data.length+')';
  119.       }
  120.       return title;
  121.       break;
  122.     case "urlCol":
  123.       if (!this.isContainer(idx)){
  124.         return this.data[idx].url;
  125.       }
  126.       else
  127.         return "";
  128.       break;
  129.     case "notesCol":
  130.       if (!this.isContainer(idx)){
  131.         if (this.data[idx].notes)
  132.           return this.data[idx].notes;
  133.         else
  134.           return "";
  135.       }
  136.       else
  137.         return "";
  138.       break;
  139.     case "labelsCol":
  140.       if (!this.isContainer(idx)){
  141.         return this.data[idx].labels;
  142.       }
  143.       else
  144.         return "";
  145.       break;
  146.     case "dateCol":
  147.       var date=new Date();
  148.       var tDate=this.data[idx].date;
  149.       date=new Date(tDate.valueOf());;
  150.       var strDate=(date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear();
  151.       return strDate;
  152.       break;
  153.     case "visitedCol":
  154.       return "";
  155.       if (!this.isContainer(idx)){
  156.         return this.data[idx].frew;
  157.       }
  158.       else
  159.         return "";
  160.       break;
  161.     case "lastVisitedCol":
  162.       return ""
  163.       break;
  164.     default:
  165.       return "";
  166.     }
  167.     return "";
  168.   },
  169.   /*
  170.    * Used for editing cells...gmarkDetails is the only one with editable cells
  171.    */
  172.   setCellText: function(idx,column,value){
  173.     //dump("setCellText("+idx+", "+column.id+" - "+value+"\n");
  174.     //tree=document.getElementById("gmarkDetails");
  175.     var refresh=false;
  176.     this.editCell.row=-1; this.editCell.col=null;
  177.     var obj1=this.data[idx], obj2=new Array();
  178.     var actionType="bookmark",action="properties";
  179.       switch (column.id){
  180.         case "mainCol":
  181.       case "nameCol":
  182.         if (this.isContainer(idx)){
  183.           actionType=null;
  184.           var newlbl=this.data[idx].fullTitle;
  185.           var pos=newlbl.lastIndexOf(this.data[idx].title);
  186.           if (pos>-1)
  187.             newlbl=newlbl.substring(0,pos)+value;
  188.             renameLabel(this.data[idx],newlbl,true,null);
  189.         }else
  190.           obj2.push({type: "title",title: this.data[idx].title});
  191.         this.data[idx].title=value;
  192.         break;
  193.       case "urlCol":
  194.         if (!this.isContainer(idx) && this.data[idx].url!=value){
  195.           obj2.push({type: "url",url: this.data[idx].url});
  196.           this.data[idx].url=value;
  197.           this.data[idx].id=0;
  198.         }
  199.         break;
  200.       case "notesCol":
  201.         if (!this.isContainer(idx)){
  202.           obj2.push({type: "notes",notes: this.data[idx].notes});
  203.           this.data[idx].notes=value;
  204.         }
  205.         break;
  206.       case "labelsCol":
  207.         if (!this.isContainer(idx)){
  208.           obj2.push({type: "labels",labels: this.data[idx].labels.toString()});
  209.           this.data[idx].labels=value.split(/\s*,\s*/);
  210.           refresh=true;
  211.         }
  212.         break;
  213.       default:
  214.         actionType=null;
  215.       }
  216.       //dump("actionType: "+actionType+" | "+obj2.length+"\n");
  217.     /* Create a bookmark action so it can be undone */
  218.     if (actionType && obj2.length>0){
  219.       if (refresh)
  220.         GMS.updateBookmark(this.data[idx],true);
  221.       else
  222.         GMS.updateRecent(this.data[idx]);
  223.       GMS.sendUpdateBookmark(this.data[idx]);
  224.       GMS.generateBkmkAction(actionType,action, obj1,obj2);
  225.     }
  226.   },
  227.   setCellValue: function(idx,column,value){
  228.     //dump("setCellValue: "+value+"\n");
  229.   },
  230.   performAction: function(action){
  231.     //dump("pa: "+action+"\n");
  232.   },
  233.   performActionOnCell: function(action,idx,column){
  234.     //dump("paoc: "+action+" - "+idx+" - "+column+"\n");
  235.   },
  236.   isContainer: function(idx)         {
  237.     if (this.data && idx<this.data.length && idx>=0 && this.data[idx].type!=null)
  238.        if (this.data[idx].type==0) return true;
  239.     return false;
  240.   },
  241.   isContainerOpen: function(idx)     { if (this.isContainer(idx)) return this.data[idx].open; else return false;},
  242.   isContainerEmpty: function(idx)    { return false; },
  243.   isSeparator: function(idx)         {
  244.     return this.data && idx<this.data.length && this.data[idx] && this.data[idx].type==-1;
  245.   },
  246.   isSorted: function()               { return false; },
  247.   isEditable: function(idx, column)  {
  248.     if (this.isContainer(idx)){
  249.       return column.id=="nameCol";
  250.     }
  251.     switch (column.id){
  252.     case "nameCol":
  253.     case "urlCol":
  254.     case "notesCol":
  255.     case "labelsCol":
  256.       return true;
  257.       break;
  258.     default:
  259.       return false;
  260.       break;
  261.     }
  262.     return false;
  263.   },
  264.   getParentIndex: function(idx) {
  265.     if (this.data && idx>=this.data.length || this.getLevel(idx)==0) return -1;
  266.     var curLevel=this.getLevel(idx);
  267.     for (var t = idx - 1; t >= 0 ; t--) {
  268.         if (this.isContainer(t) && this.getLevel(t)<curLevel) return t;
  269.     }
  270.     return -1;
  271.   },
  272.   getParentLabel: function(idx){
  273.     var parent=this.getParentIndex(idx);
  274.     if (parent>-1){
  275.       return this.data[parent].fullTitle;
  276.     }
  277.     else{
  278.       if (this.parentLbl==null)
  279.         return "";
  280.       else
  281.         return this.parentLbl;
  282.     }
  283.   },
  284.   getLevel: function(idx) {
  285.     if (this.isSeparator(idx)) return 0;
  286.     if (idx>-1 && this.data && idx<this.data.length){
  287.       var level = this.data[idx].level;
  288.       if (this.type=="details" && typeof level!='undefined')
  289.         level--;
  290.       else if (typeof level=='undefined')
  291.         level=0;
  292.       return level;
  293.     }
  294.     else{
  295.       return -1;
  296.     }
  297.   },
  298.   hasNextSibling: function(idx, after) {
  299.     var thisLevel = this.getLevel(idx);
  300.     for (var t = idx + 1; t < this.data.length; t++) {
  301.       if (!this.isSeparator(t)){
  302.         var nextLevel = this.getLevel(t)
  303.         if (nextLevel == thisLevel) return true;
  304.         else if (nextLevel < thisLevel) return false;
  305.       }
  306.     }
  307.     return false;
  308.   },
  309.   closeContainer: function(idx){
  310.     this.rowsOpen--;
  311.     this.data[idx].open = false;//Not open
  312.  
  313.     var thisLevel = this.getLevel(idx);
  314.     var deletecount = 0;
  315.     for (var t = idx + 1; t < this.data.length; t++) {
  316.       if (this.getLevel(t) > thisLevel) {
  317.       if (this.data[t].type==0) this.data[t].open=false;
  318.       deletecount++;
  319.       }
  320.     else break;
  321.     }
  322.     if (deletecount) {
  323.       this.data.splice(idx + 1, deletecount);
  324.     }
  325.     return deletecount;
  326.   },
  327.   openContainer: function(idx){
  328.     this.data[idx].open = true;
  329.     if (this.data[idx].level==0) this.rowsOpen++;
  330.  
  331.   var toinsert = this.data[idx].data;
  332.   var lvl=this.data[idx].level+1;
  333.   if (toinsert || true){
  334.       for (var i = 0; i < toinsert.length; i++) {
  335.       if (toinsert[i].type!=null && toinsert[i].type==0)
  336.         this.data.splice(idx + i + 1, 0, toinsert[i]);
  337.       else{
  338.           if (this.type!="labels")
  339.             this.data.splice(idx + i + 1, 0,  new BookmarkData(2,toinsert[i],lvl));
  340.           else
  341.             return i;
  342.       }
  343.       }
  344.       return toinsert.length;
  345.   }
  346.   else
  347.     return 0;
  348.   },
  349.   expand: function(idx,fromPopup){
  350.     var start=idx;
  351.     var length=0;
  352.     var level=this.data[idx].level;
  353.     if (!this.isContainerOpen(idx))
  354.       length+=this.openContainer(idx);
  355.     idx++;
  356.     while(idx<this.data.length && this.data[idx].level>level){
  357.       if (this.isContainer(idx)){
  358.         if (!this.isContainerOpen(idx))
  359.           length+=this.openContainer(idx);
  360.       }
  361.       idx++;
  362.     }
  363.     this.treeBox.rowCountChanged(start + 1, length);
  364.     if (fromPopup){
  365.     var lastRow=this.treeBox.getLastVisibleRow();
  366.     if (idx>lastRow){
  367.       //dump("scroll down!\n");
  368.       this.treeBox.scrollByLines(idx-lastRow);
  369.     }
  370.     }
  371.     return length;
  372.   },
  373.   toggleOpenState: function(idx) {
  374.     if (!this.isContainer(idx)) return;
  375.  
  376.     if (this.data[idx].open) {
  377.        //We close it
  378.         var deletecount=this.closeContainer(idx);
  379.         if (deletecount)
  380.           this.treeBox.rowCountChanged(idx + 1, -deletecount);
  381.     }
  382.     else {
  383.       var length=this.openContainer(idx);
  384.       this.treeBox.rowCountChanged(idx + 1, length);
  385.       var firstRow=this.treeBox.getFirstVisibleRow();
  386.       var lastRow=this.treeBox.getLastVisibleRow();
  387.       if (idx+1+length>lastRow){
  388.         if (length+1>lastRow-firstRow)
  389.           length=lastRow-firstRow-1;
  390.         this.treeBox.scrollByLines((idx+1+length)-lastRow);
  391.       }
  392.     }
  393.     this.selection.select(idx);
  394.   },
  395.   openAll: function(change){
  396.     if (change!=false)
  397.       this.treeBox.beginUpdateBatch();
  398.     for (var i=0;i<this.data.length;i++){
  399.     if (this.isContainer(i) && !this.isContainerOpen(i)){
  400.       this.openContainer(i);
  401.     }
  402.   }
  403.   if (change!=false)
  404.     this.treeBox.endUpdateBatch();
  405.   },
  406.   closeAll: function(change){
  407.     if (change!=false)
  408.       this.treeBox.beginUpdateBatch();
  409.     for (var i=0;i<this.data.length;i++){
  410.       if (this.isContainerOpen(i)){
  411.         this.closeContainer(i);
  412.       }
  413.     }
  414.     if (change!=false)
  415.       this.treeBox.endUpdateBatch();
  416.   },
  417.   toggleAll: function(){
  418.     this.treeBox.beginUpdateBatch();
  419.     if (this.rowsOpen==0){
  420.       //Open all rows
  421.       this.openAll(false);
  422.     }
  423.     else{
  424.       //Close all rows
  425.       this.closeAll(false);
  426.     }
  427.     this.treeBox.endUpdateBatch();
  428.   },
  429.   getImageSrc: function(idx, column) {
  430.     if (this.isSeparator(idx)) return null;
  431.     if (!(typeof GMS == "undefined")){
  432.       if (!GMS.showIcons || !GMS.showFavs) return null;
  433.       var bkmk;
  434.       if (this.isContainer(idx)){
  435.         if (this.data[idx].bkmk==null){
  436.           return null;
  437.         }
  438.         else{
  439.           bkmk=this.data[idx].bkmk;
  440.         }
  441.       }
  442.       else if (this.data){
  443.         bkmk=this.data[idx];
  444.       }
  445.       if (column.id=="mainCol" || column.id=="nameCol")
  446.         if (bkmk)
  447.           return bkmk.image;
  448.     }
  449.     return null;
  450.   },
  451.   getProgressMode : function(idx,column) {},
  452.   getCellValue: function(idx, column) {},
  453.   cycleHeader: function(col, elem) {},
  454.   selectionChanged: function() {},
  455.   cycleCell: function(idx, column) {},
  456.   //performAction: function(action) {},
  457.   //performActionOnCell: function(action, index, column) {},
  458.   getRowProperties: function(idx, column, prop) {},
  459.   getCellProperties: function(idx, column, prop) {
  460.     if ((column.id=="mainCol" || column.id=="nameCol") && !this.isSeparator(idx) && this.data
  461.         && !(typeof Components == "undefined")){
  462.       var aserv=Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
  463.       if (GMS.showIcons==true){
  464.         prop.AppendElement(aserv.getAtom("showIcon"));
  465.         if (GMS.readerLabel==this.data[idx].fullTitle)
  466.           prop.AppendElement(aserv.getAtom("starredInReader"));
  467.       }
  468.       if (this.type=="labels" && this.data[idx].type==0){
  469.         if (this.data[idx].data[0].type!=0){
  470.           prop.AppendElement(aserv.getAtom("hideTwisty"));
  471.         }
  472.       }
  473.     }
  474.   },
  475.   getColumnProperties: function(column, element, prop) {},
  476.  
  477.   canDrop : function(idx, orient) {
  478.     return true;
  479.   },
  480.   drop : function(index, orient) {
  481.     if ( !treeDrag) {
  482.       if (gmarksDragObserver.data){
  483.         gmarksDragObserver.treeDrop(index,this.getTree());
  484.       }
  485.       return;
  486.     }
  487.     try{
  488.     var label="";/* Label dropped onto or under */
  489.     var inside=false;
  490.     if(index>-1 && index<this.data.length){
  491.       if (this.isContainer(index))
  492.         label=this.data[index].fullTitle;
  493.       else if (this.data[index].type==2){
  494.         var parent=this.getParentIndex(index);
  495.         if (parent != -1)
  496.           label=this.data[parent].fullTitle;
  497.       else
  498.         label=this.getParentLabel(index);
  499.       inside=true;
  500.       }
  501.     }
  502.     if (label==GMS.strbundle.GetStringFromName("mostrecent") ||
  503.         label==GMS.strbundle.GetStringFromName("mostused")){
  504.       label="";
  505.     }
  506.     //dump("drag to label: "+label+"\n");
  507.     var selection=dragSource.selection;
  508.     var selected=dragSource.selectedData;
  509.     //Add Label to Bookmark(s)
  510.     /* Move to root */
  511.     var actionLength_Start=GMS.actionHist.length;
  512.     if (label==null || label=="" || label==this.parentLbl){
  513.       //dump("delete label drag and drop\n");
  514.       var offset=0;
  515.       for (var i=0;i<selected.length;i++){
  516.         var dragIndex=selected[i]+offset,startRows=this.rowCount;
  517.         if (dragSource.isContainer(dragIndex)){
  518.           var parent=dragSource.getParentLabel(dragIndex);
  519.           if (parent!=this.parentLbl && parent!=""){
  520.             var newTitle=dragSource.data[dragIndex].title;
  521.             GMS.onRenameLabel(dragSource.data[dragIndex].fullTitle,dragSource.data[dragIndex].title);
  522.           }
  523.         }
  524.         else if (!dragSource.isSeparator(dragIndex)){
  525.           var bm=new Array();
  526.           bm.push(dragSource.data[dragIndex]);
  527.           var children=new Array();
  528.             for (var i=0;i<bm.length;i++){
  529.               for (var n=0;n<bm[i].labels.length;n++){
  530.                 children.push({bkmk:bm[i],label: bm[i].labels[n]});
  531.                 GMS.removeLabelFromBookmark(bm[i],bm[i].labels[n],false);
  532.                 GMS.actionHist.pop();
  533.               }
  534.             }
  535.             /* Create a bookmark action so it can be undone */
  536.           this.generateBkmkAction("label","delete",children);
  537.         }
  538.         offset+=this.rowCount-startRows;
  539.       }
  540.     }
  541.     /* Move data, don't copy */
  542.     else if (keyEvent==null || keyEvent.ctrlKey==false){
  543.       //dump("move don't copy\n");
  544.       var offset=0;
  545.       for (var i=0;i<selected.length;i++){
  546.         var dragIndex=selected[i]+offset,startRows=this.rowCount;
  547.         var oldLabel="";
  548.         if (dragSource.isContainer(dragIndex)){
  549.           oldLabel=dragSource.data[dragIndex].fullTitle;
  550.         }
  551.         else
  552.           oldLabel=dragSource.getParentLabel(dragIndex);
  553.         if (oldLabel!=label){
  554.           if (dragSource.isContainer(dragIndex)){
  555.             if (oldLabel!=null && oldLabel!="")
  556.               if (inside)
  557.                 GMS.onRenameLabel(oldLabel,label+GMS.nestedChar+dragSource.data[dragIndex].title,false);
  558.               else
  559.                 GMS.onRenameLabel(oldLabel,label,false);
  560.           }
  561.           else{
  562.             var bm=new Array();
  563.             bm.push(dragSource.data[dragIndex]);
  564.             addLabelFromDaD(bm,label,false);
  565.             if (oldLabel!="" && oldLabel!=null){
  566.               GMS.removeLabelFromBookmark(dragSource.data[dragIndex],oldLabel,false);
  567.               GMS.actionHist.pop();
  568.             }
  569.           }
  570.         }
  571.         offset+=this.rowCount-startRows;
  572.       }
  573.     }
  574.     /* Copy */
  575.     else{
  576.       var offset=0;
  577.       for (var i=0;i<selected.length;i++){
  578.         var dragIndex=selected[i]+offset,startRows=this.rowCount;
  579.         var bm=new Array();
  580.         if (dragSource.isContainer(dragIndex)){
  581.           bm=dragSource.data[dragIndex].data;
  582.           if (inside)
  583.             addLabelFromDaD(bm,label+GMS.nestedChar+dragSource.data[dragIndex].title,false);
  584.           else
  585.             addLabelFromDaD(bm,label,false);
  586.         }
  587.         else{
  588.           bm.push(dragSource.data[dragIndex]);
  589.           addLabelFromDaD(bm,label,false);
  590.         }
  591.         offset+=this.rowCount-startRows;
  592.       }
  593.       keyEvent=null;
  594.     }
  595.     var actionLength_End=GMS.actionHist.length;
  596.     var actionLength_Diff=actionLength_End-actionLength_Start;
  597.     var dndActions=GMS.actionHist.slice(actionLength_Start,actionLength_Diff);
  598.     GMS.generateBkmkAction("all","complex action",dndActions);
  599.  
  600.     GMS.doCommand("quickrefresh");
  601.     /* Update tree selection */
  602.     if (dragSource==this){
  603.       dragSource.selection.clearSelection();
  604.     }
  605.     }catch(e){dump(e+"\n");}
  606.   },
  607.   
  608.   //Custom stuff
  609.   getURL: function(idx){return this.data[idx].url;},
  610.   getBookmark: function(idx){
  611.     return this.data[idx];
  612.   },
  613.   restoreContainers: function(lbls,toSelect){
  614.     if (!lbls){
  615.       var savedPref = prefs.getCharPref(".labels");
  616.       lbls = savedPref.split(/\s*,\s*/);
  617.     }
  618.     this.rowsOpen=0;
  619.     for (var i=0;i<this.data.length;i++){
  620.       if (this.data[i].type!=null && this.data[i].type==0){
  621.         if (toSelect && this.data[i].title == toSelect){
  622.           this.selection.select(i);
  623.           toSelect = null;
  624.         }
  625.         var idx=lbls.indexOf(this.data[i].fullTitle);
  626.         if (idx>-1){
  627.           this.openContainer(i);
  628.           lbls.splice(idx,1);
  629.         }
  630.       }
  631.     }
  632.   },
  633.   getOpened: function(){
  634.     var lbls=new Array();
  635.     for (var i=0;i<this.data.length;i++){
  636.       if (this.isContainerOpen(i)){
  637.         lbls.push(this.data[i].fullTitle);
  638.       }
  639.     }
  640.     return lbls;
  641.   },
  642.   saveOpened: function(){
  643.     prefs.setCharPref(".labels",this.getOpened().join(","));
  644.   },
  645.   //Only called in the organize window
  646.   sortBy: function(type){
  647.     this.treeBox.beginUpdateBatch();
  648.     var openedLbls=this.getOpened();
  649.     this.closeAll(false);
  650.     if (this.sortinfo[0]==type){
  651.       this.sortinfo[1]=this.sortinfo[1]==0?1:0;
  652.       if (this.sortinfo[1]==1)
  653.         document.getElementById(this.sortinfo[0]+"Col").setAttribute(
  654.           "sortDirection","descending");
  655.       else if (this.sortinfo[1]==0)
  656.         document.getElementById(this.sortinfo[0]+"Col").setAttribute(
  657.           "sortDirection","ascending");
  658.     }
  659.     else{
  660.       document.getElementById(this.sortinfo[0]+"Col").setAttribute("sortActive","false");
  661.       document.getElementById(this.sortinfo[0]+"Col").setAttribute(
  662.           "sortDirection","neutral");
  663.       this.sortinfo[0]=type;
  664.       document.getElementById(this.sortinfo[0]+"Col").setAttribute("sortActive","true");
  665.       document.getElementById(this.sortinfo[0]+"Col").setAttribute(
  666.           "sortDirection","ascending");
  667.       this.sortinfo[1]=0;
  668.     }
  669.     this._sortBy(treeView.data,type,this.sortinfo[1]);
  670.     this.restoreContainers(openedLbls);
  671.  
  672.     this.treeBox.endUpdateBatch();
  673.   },
  674.   //the actual sort
  675.   _sortBy: function(aData,type,order){
  676.     var n;
  677.     for (var i=0;i<aData.length;i++){
  678.       var obj=aData[i];
  679.       if (obj.type!=null && obj.type==0){
  680.           this._sortBy(obj.data,type);
  681.         }
  682.     }
  683.     switch(type){
  684.       case "name":
  685.         var lastX
  686.         aData.sort(function (x, y){
  687.           if ((x.type!=null && x.type==0) && (y.type==null || y.type!=0)){//X=Folder, Y==Bookmark
  688.             return -1;
  689.           }
  690.           else if ((y.type!=null && y.type==0) && (x.type==null || x.type!=0)){//X==Bookmark, Y==Folder
  691.             return 1;
  692.           }
  693.           var compare=0;
  694.           if (x.title.toLowerCase() < y.title.toLowerCase())
  695.             compare=-1;
  696.           else if (x.title.toLowerCase() > y.title.toLowerCase())
  697.             compare=1;
  698.           return order==1?-compare:compare;
  699.         });
  700.         break;
  701.       case "url":
  702.         aData.sort(function (x, y){
  703.           if ((x.type!=null && x.type==0) && (y.type==null || y.type!=0)){//x=label y=bookmark
  704.             return -1;
  705.           }
  706.           else if ((y.type==null || y.type==0) && (x.type!=null && x.type!=0)){
  707.             return 1;
  708.           }
  709.           else if ((y.type!=null && y.type==0) && (x.type!=null && x.type==0)){
  710.             var compare=0;
  711.             if (x.title.toLowerCase() > y.title.toLowerCase())
  712.             compare=-1;
  713.           else if (x.title.toLowerCase() < y.title.toLowerCase())
  714.             compare=1;
  715.           return order==0?-compare:compare;
  716.           }
  717.           else{
  718.             var compare=0;
  719.             if (x.url < y.url)
  720.             compare=1;
  721.           else if (x.url > y.url)
  722.             compare=-1;
  723.           return order==0?-compare:compare;
  724.           }
  725.         });
  726.         break;
  727.       case "date":
  728.         aData.sort(function (x, y){
  729.           //Folder vs Bookmark
  730.           if ((x.type!=null && x.type==0) && (y.type==null || y.type!=0)){//x=label y=bookmark
  731.             return -1;
  732.           }
  733.           //Bookmark vs Folder
  734.           else if ((x.type==null || x.type!=0) && (y.type!=null && y.type==0)){
  735.             return 1;
  736.           }
  737.           else{
  738.             var compare=0;
  739.             if (x.date > y.date)
  740.             compare=-1;
  741.           else if (x.date < y.date)
  742.             compare=1;
  743.           return order==0?compare:-compare;
  744.           }
  745.         });
  746.         break;
  747.       case "notes":
  748.         aData.sort(function (x, y){
  749.           if ((x.type!=null && x.type==0) && (y.type==null || y.type!=0)){//x=label y=bookmark
  750.             return -1;
  751.           }
  752.           else if ((y.type!=null && y.type==0) && (x.type==null || x.type!=0)){
  753.             return 1;
  754.           }
  755.           else if ((y.type!=null && y.type==0) && (x.type!=null && x.type==0)){
  756.             var compare=0;
  757.             if (x.title.toLowerCase() < y.title.toLowerCase())
  758.             compare=1;
  759.           else if (x.title.toLowerCase() > y.title.toLowerCase())
  760.             compare=-1;
  761.           compare=order==0?-compare:compare;
  762.           return compare;
  763.           }
  764.           else if (((x.notes!=null && x.notes.length>0)) &&
  765.             (y.notes==null || y.notes.length==0)){
  766.             return order==0?-1:1;
  767.           }
  768.           else if (((y.notes!=null && y.notes.length>0)) &&
  769.             (x.notes==null || x.notes.length==0)){
  770.             return order==1?-1:1;
  771.           }
  772.           else if (x.notes==y.notes){
  773.             return 0;
  774.           }
  775.           else{
  776.             var compare=0;
  777.             if (x.notes.toLowerCase() < y.notes.toLowerCase())
  778.             compare=1;
  779.           else if (x.notes.toLowerCase() > y.notes.toLowerCase())
  780.             compare=-1;
  781.           return order==0?-compare:compare;
  782.           }
  783.         });
  784.         break;
  785.       }
  786.   },
  787.   get rowCount()                     { return this.loading?0:this.data.length;}
  788. };
  789. function expand(event){
  790.   var tree=document.popupNode;
  791.   if (tree.tagName!="tree") tree = tree.parentNode;
  792.   getTreeView(tree).expand(pops.getLabelIndex(),true);
  793. }
  794.  
  795. //Gets the tree view with my added methods & vars, the standard tree view interface doesn't expose all methods
  796. function getTreeView(tree){
  797.   if (typeof tree == 'string'){
  798.     if (tree=="complete" || tree=="details")
  799.       return treeView;
  800.     else
  801.       return lblsTreeView;
  802.   }
  803.   else{
  804.     var treeId=tree.getAttribute('id');
  805.     if (treeId=="gmarkList" || treeId=="gmarkDetails")
  806.       return treeView;
  807.     else
  808.       return lblsTreeView;
  809.   }
  810. }
  811. //Detects a right click on a mac too...
  812. function isRightClick(event){
  813.   if (event.button==2)
  814.     return true;
  815.   if (navigator.appVersion.indexOf("Mac")!=-1){
  816.     if (event.ctrlKey==true && event.button==0)
  817.       return true;
  818.   }
  819.   return false;
  820. }
  821. function gmTreeContextShowing(event){
  822.   var tree=document.popupNode;
  823.   if (tree.tagName!="tree") tree=tree.parentNode;
  824.   var row = {}, col = {}, obj = {};
  825.   var view=getTreeView(tree);
  826.   var visibleData=view.data;
  827.   var popup=event.target;
  828.   var selectedIndexes=view.selectedData;
  829.   if (selectedIndexes.length==0) return false;
  830.   var selected = [];
  831.   selectedIndexes.forEach(function(sel,idx){
  832.     selected.push(visibleData[sel]);
  833.     selected[idx].parent = view.getParentLabel(sel);
  834.   });
  835.   return gmContextShowing(popup,selected);
  836. }
  837. function gmMouseMoved(event){
  838.   this.lastX = event.clientX;
  839.   this.lastY = event.clientY;
  840. }
  841. function gmTreeTooltipShowing(event){
  842.   var tree=document.tooltipNode;
  843.   if (tree.tagName!="tree") tree=tree.parentNode;
  844.   var row = {}, col = {}, obj = {};
  845.   tree.treeBoxObject.getCellAt(this.lastX, this.lastY, row, col, obj);
  846.   var view=getTreeView(tree);
  847.   var titleField = document.getElementById("gm-tooltip-title");
  848.   var notesField = document.getElementById("gm-tooltip-notes");
  849.  
  850.   if (row.value>-1 && row.value < view.data.length && !view.isSeparator(row.value)){
  851.     //while(titleField.lastChild) titleField.removeChild(titleField.lastChild);
  852.     //titleField.appendChild(document.createTextNode(view.data[row.value].title))
  853.     //while(notesField.lastChild) notesField.removeChild(notesField.lastChild);
  854.     titleField.setAttribute("value",view.data[row.value].title);
  855.     if (view.data[row.value].notes){
  856.       notesField.hidden = false;
  857.       //notesField.appendChild(document.createTextNode(view.data[row.value].notes));
  858.       notesField.setAttribute("value",view.data[row.value].notes);
  859.     }
  860.     else
  861.       notesField.hidden = true;
  862.     return true;
  863.   }
  864.   return false;
  865. }
  866.  
  867. function gmContextShowing(popup, selected){
  868.   var mrecent=GMS.strbundle.GetStringFromName("mostrecent");
  869.   var mfreq=GMS.strbundle.GetStringFromName("mostused");
  870.   var hideBkmks=false;
  871.   var hideLabels=false;
  872.   var hideRemoveLabel=false;
  873.   var hideBkmkModifiers=false;
  874.   var hideRenameAndDelete=false;
  875.   var items=popup.getElementsByTagName("menuitem");
  876.   var separators=popup.getElementsByTagName("menuseparator");
  877.   selected.forEach(function(bkmk,idx,arr){
  878.     if (bkmk.type!=0){//Bookmark
  879.       //The Google Reader label is a fake label, so we can't remove it
  880.       //As are the Most Recent and Most Used
  881.       var pLabel = bkmk.parent;
  882.       if (bkmk.labels.indexOf(GMS.readerLabel)>-1 ||
  883.           pLabel==mrecent || pLabel==mfreq){
  884.         hideRemoveLabel=true;
  885.       }
  886.       if (bkmk.labels.indexOf(GMS.readerLabel)!=-1){
  887.         hideBkmkModifiers=true;
  888.       }
  889.       hideLabels=true;
  890.     }
  891.     else{//Label/Folder/Tag...whatever you want to call it
  892.       var title=bkmk.fullTitle;
  893.       if (title==GMS.unlabeled || title==GMS.readerLabel ||
  894.           title==mrecent || title==mfreq){
  895.         hideRenameAndDelete=true;
  896.       }
  897.       hideBkmks=true;
  898.     }
  899.   },this);
  900.   //dump("hide bkmks: "+hideBkmks+"|"+hideLabels+"\n");
  901.   for (var i=items.length-1;i>=0;i--){
  902.     if (items[i].id.substring(0,3)=="lbl"){//labels
  903.       if (hideLabels)
  904.         items[i].hidden=true;
  905.       else{
  906.         var name=items[i].id.substring(3);
  907.         if (hideRenameAndDelete && (
  908.             name=="rename"||
  909.             name=="del" ||
  910.             name=="delbkmk"))
  911.           items[i].hidden=true
  912.         else
  913.           items[i].hidden=false;
  914.       }
  915.     }
  916.     else{//bkmks
  917.       if (hideBkmks && !hideLabels)
  918.         items[i].hidden=true;
  919.       else{
  920.         var name=items[i].id.substring(4);
  921.         if (hideRemoveLabel && name=="removelbl")
  922.           items[i].hidden=true;
  923.         else if (hideBkmks && (
  924.             name=="fav" ||
  925.             name=="rename" ||
  926.             name=="update" ||
  927.             name=="newlbl" ||
  928.             name=="removelbl" ||
  929.             name=="edit" ||
  930.             name=="open"
  931.             )){
  932.           items[i].hidden=true;
  933.         }
  934.         else if (hideBkmkModifiers && (
  935.             name=="fav" ||
  936.             name=="rename" ||
  937.             name=="update" ||
  938.             name=="newlbl" ||
  939.             name=="del"))
  940.           items[i].hidden=true;
  941.         else
  942.           items[i].hidden=false;
  943.       }
  944.     }
  945.   }
  946.   separators[0].hidden=(hideBkmkModifiers || hideRenameAndDelete);
  947.   separators[1].hidden=(hideBkmks && hideLabels);
  948.   return true;
  949. }
  950. /*
  951.  Open bookmarks, switch tree views, & end organize edit
  952. */
  953. function mouseClick(event){
  954.   var tree=event.target.parentNode;
  955.   if (tree){
  956.     var row = {}, col = {}, obj = {};
  957.     var view=getTreeView(tree);
  958.     tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, obj);
  959.     var visibleData=view.data;
  960.     if (!view.isSeparator(row.value)){
  961.       //For inline editing in the organize window
  962.       if (view.type=="details" && editField.hidden==false){
  963.         if (obj.value!="text" || editRow!=row.value || editCol!=col.value){
  964.           fieldChange();
  965.         }
  966.         else{
  967.           return;
  968.         }
  969.       }
  970.       if (row.value>=0 && row.value<visibleData.length){
  971.         if (obj.value){
  972.           var sel;
  973.           //if (!row.value || row.value<0)//(obj.value.toString()!='twisty')/*The selection isn't updated when middle clicked*/
  974.           //  sel=tree.currentIndex;
  975.           //else
  976.             sel=row.value;
  977.           //view.selection.select(sel);
  978.           if (!tree.view.isContainer(sel)){//Bookmark
  979.               if (!isRightClick(event)){//if (event.button<2){
  980.                 //Open the bookmark if its from the sidebar...
  981.                 if (tree.getAttribute("id")=="gmarkList"){
  982.                   openBookmark(view.getURL(sel),event);
  983.                 }
  984.             }
  985.           }
  986.           else{//Label/Folder/Tag...whatever you want to call it
  987.             var where=whereToOpenLink(event);
  988.             if (where=="tab" || where=="tabshifted" || where=="window")//Middle click
  989.               openInTabs(event);
  990.             else if (event.button==0){
  991.               if (tree.getAttribute("id")=="gmarkList"){
  992.                 if (view.data[sel].bkmk!=null)
  993.                   if (obj.value.toString()!='twisty'){
  994.                     openBookmark(view.data[sel].bkmk.url,event);
  995.                   }
  996.               }
  997.               /*
  998.                * label tree only(organize window)
  999.                * Changes the details tree based on the newly selected label
  1000.                */
  1001.               switchView(tree);
  1002.             }
  1003.           }
  1004.         }
  1005.       }
  1006.     }
  1007.   }
  1008. }
  1009. function switchView(tree){
  1010.   if (tree.getAttribute("id")=="gmarkLabels"){
  1011.     fieldChange();
  1012.     treeView.treeBox.beginUpdateBatch();
  1013.     treeView.parentLbl=lblsTreeView.data[tree.currentIndex].fullTitle;
  1014.     treeView.data=getTreeData(treeView.parentLbl,true,treeView.type);
  1015.     treeView.treeBox.endUpdateBatch();
  1016.     treeView.openAll();
  1017.   }
  1018. }
  1019. function doubleClick(event){
  1020.   var tree=event.target.parentNode;
  1021.   var treeBox = tree.treeBoxObject;
  1022.   var row = {};
  1023.   var col = {};
  1024.   var obj = {};
  1025.   treeBox.getCellAt(event.clientX,event.clientY,row,col,obj);
  1026.   if (!tree.editingColumn && row.value!=-1 && col.value!=null &&
  1027.       getTreeView(event.target.parentNode).isEditable(row.value,col.value))
  1028.     setEditModeditMode(row.value,col.value,true);
  1029. }
  1030. function setEditMode(row,column,val){
  1031.   if (val){
  1032.     if (row < 0) return;
  1033.  
  1034.     if (editRow >= 0) assignValueToCell(editField.value,true);
  1035.     editField.hidden=false;
  1036.     editRow=row; editCol=column;
  1037.     var treeBox = treeView.treeBox;
  1038.     var tree=treeBox.treeBody.parentNode;
  1039.     var outx = {}, outy = {}, outwidth = {}, outheight = {};
  1040.     var coords = treeBox.getCoordsForCellItem(row, column, "text",
  1041.                                     outx, outy, outwidth, outheight);
  1042.     var style = window.getComputedStyle(editField, "");
  1043.     var topadj = parseInt(style.borderTopWidth) + parseInt(style.paddingTop);
  1044.     offset=tree.columns["nameCol"].element.boxObject.height;
  1045.     //outheight.value=26;
  1046.     outy.value+=offset;//30;
  1047.     editField.top = outy.value - topadj;
  1048.  
  1049.     var left = outx.value;
  1050.     editField.left = left;
  1051.     editField.height = outheight.value + topadj +
  1052.              parseInt(style.borderBottomWidth) +
  1053.              parseInt(style.paddingBottom);
  1054.  
  1055.     coords = treeBox.getCoordsForCellItem(row, column, "cell",
  1056.                                       outx, outy, outwidth, outheight);
  1057.     editField.width = outwidth.value - (left - outx.value);
  1058.     editField.value = tree.view.getCellText(row, column);
  1059.     editField.addEventListener("keydown", fieldKeyDown, false);
  1060.     editField.addEventListener("blur", fieldChange, true);
  1061.     editOriginalValue = editField.value;
  1062.     var selectText = function selectText() {
  1063.         editField.select();
  1064.         editField.inputField.focus();
  1065.     }
  1066.     setTimeout(selectText, 0);
  1067.     tree.setAttribute("editing","true");
  1068.   }
  1069.   else {
  1070.     //dump("setEditMode - REMOVE\n");
  1071.     var treeBox = treeView.treeBox;
  1072.     var tree=treeBox.treeBody.parentNode;
  1073.     tree.removeAttribute("editing");
  1074.  
  1075.     editField.hidden=true;
  1076.     editField.removeEventListener("keydown", fieldKeyDown, false);
  1077.     editField.removeEventListener("blur", fieldChange, true);
  1078.     editField.blur();
  1079.     treeView.selection.select(editRow);
  1080.     editRow=-1; editCol = null;
  1081.   }
  1082. }
  1083. function assignValueToCell(value, acceptMode){
  1084.   if (editRow == -1 || editField.hidden) return;
  1085.   if (value!=null){
  1086.     var update=value!=editOriginalValue && acceptMode;
  1087.     if (update){
  1088.       treeView.setCellText(editRow,editCol,value);
  1089.     }
  1090.   }
  1091.   if (value==null || acceptMode){
  1092.     setEditMode(0,0,false);//"normal"
  1093.   }
  1094. }
  1095. function fieldKeyDown(event){
  1096.     if (event.keyCode == 13){
  1097.       assignValueToCell(editField.value,true);
  1098.     }
  1099.     if (event.keyCode == 27){
  1100.       assignValueToCell(null,false);
  1101.     }
  1102.     event.stopPropagation();
  1103. }
  1104. function fieldChange(event){
  1105.     assignValueToCell(editField.value,true);
  1106. }
  1107. function keyPress(event){
  1108.   //dump("keypress: "+event.keyCode+"\n");
  1109.   var tree=event.target;
  1110.   if (tree.editingColumn!=null) return;
  1111.   var sel=tree.currentIndex;
  1112.   var view=getTreeView(tree);
  1113.   var visibleData=view.data;
  1114.   if (sel<0 || sel>visibleData.length) return;
  1115.   var container=view.isContainer(sel);
  1116.   var keys=Components.interfaces.nsIDOMKeyEvent;
  1117.   //dump("enter: "+keys.DOM_VK_RETURN+"\n");
  1118.   switch (event.keyCode){
  1119.     case keys.DOM_VK_RETURN:
  1120.     case keys.DOM_VK_ENTER:
  1121.       //dump("enter key press\n");
  1122.       if (!container){
  1123.         openBookmarks(event);
  1124.         //openBookmark(getTreeView(tree).getURL(sel),event);
  1125.       }
  1126.       break;
  1127.     case keys.DOM_VK_DELETE:
  1128.       removeBookmarks(event);
  1129.       break;
  1130.     case keys.DOM_VK_LEFT:
  1131.     case keys.DOM_VK_UP:
  1132.     case keys.DOM_VK_RIGHT:
  1133.     case keys.DOM_VK_DOWN:
  1134.       setTimeout(function(){switchView(tree);},10);
  1135.       break;
  1136.     default:
  1137.       //dump(event.keyCode+"\n");
  1138.  
  1139.   }
  1140.  
  1141. }
  1142. function openBookmarks(event){
  1143.   var bookmarkPrefs=Components.classes["@mozilla.org/preferences-service;1"].
  1144.                             getService(Components.interfaces.nsIPrefService).getBranch("extensions.tabmix.");
  1145.   var bkmkNewTab;
  1146.   try{
  1147.     bkmkNewTab=bookmarkPrefs.getBoolPref("opentabfor.bookmarks");
  1148.   }
  1149.   catch(e){bkmkNewTab=false;}
  1150.   bkmkNewTab=bkmkNewTab || prefs.getBoolPref('.openinnewtab');
  1151.   var where=bkmkNewTab?("tab"+event.shiftKey?"shifted":""):whereToOpenLink(event);
  1152.   openBookmarksIn(event,where);
  1153. }
  1154. function openBookmarksIn(event,where){
  1155.   var tree;
  1156.   if (event.target.tagName=="tree")
  1157.     tree=event.target;
  1158.   else if (event.target.parentNode.tagName=="tree")
  1159.     tree=event.target.parentNode;
  1160.   else{
  1161.     tree=document.popupNode;
  1162.     if (tree.tagName!="tree")
  1163.       tree = tree.parentNode;
  1164.   }
  1165.   var view=getTreeView(tree);
  1166.   var selected=view.selectedData;
  1167.   var actionLength_Start=GMS.actionHist.length;
  1168.   var offset=0;
  1169.   if (where=="current" && selected.length>1)
  1170.     where="tab";
  1171.   var data=selected.map(function(idx,index,arr){
  1172.     return view.data[idx];
  1173.   });
  1174.   var mainWindow = null, browser = null;
  1175.   var replace =  (data.length>0 || ("type" in data[0] && data[0].type==0)) && prefs.getBoolPref(".loadLabelAndReplace");
  1176.   var canReplace = false;
  1177.   if (replace){
  1178.     data.forEach(function(item,idx,arr){
  1179.       if ("type" in item && item.type==0)
  1180.         canReplace = true;
  1181.     });
  1182.   }
  1183.   replace = replace && canReplace;
  1184.   
  1185.   if (replace && where != "window"){
  1186.     /*
  1187.      This needs to work for both the sidebar and the organize window
  1188.      First try is for the sidebar, opener is for the organize window.
  1189.     */
  1190.     mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  1191.                    .getInterface(Components.interfaces.nsIWebNavigation)
  1192.                    .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
  1193.                    .rootTreeItem
  1194.                    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  1195.                    .getInterface(Components.interfaces.nsIDOMWindow)
  1196.     if (!(mainWindow && "getBrowser" in mainWindow)){
  1197.       mainWindow = opener;
  1198.     }
  1199.     if (mainWindow && "getBrowser" in mainWindow){
  1200.       browser = mainWindow.getBrowser();
  1201.       var childNodes = browser.tabContainer.childNodes;
  1202.       for (var i = childNodes.length - 1; i >= 0; --i) {
  1203.         browser.removeTab(childNodes[i]);
  1204.       }
  1205.     }
  1206.   }
  1207.   openBookmarkItems(data,view,where);
  1208.   if (replace && browser){
  1209.     browser.removeTab(browser.tabContainer.childNodes[0]);
  1210.   }
  1211. }
  1212. function openBookmarkItems(data,view,where){
  1213.   if (data.length>1 && where=="tab") where = "tabshifted";
  1214.   data.forEach(function(item,idx,arr){
  1215.     if ("type" in item && item.type==0)//isContainer
  1216.       openBookmarkItems(item.data,view,"tabshifted");
  1217.     else
  1218.       openUILinkIn(item.url,where);
  1219.   },this);
  1220. }
  1221. function openBookmark(url,event){
  1222.   var bookmarkPrefs=Components.classes["@mozilla.org/preferences-service;1"].
  1223.                             getService(Components.interfaces.nsIPrefService).getBranch("extensions.tabmix.");
  1224.   var bkmkNewTab;
  1225.   try{
  1226.     bkmkNewTab=bookmarkPrefs.getBoolPref("opentabfor.bookmarks");
  1227.   }
  1228.   catch(e){bkmkNewTab=false;}
  1229.   bkmkNewTab=bkmkNewTab || prefs.getBoolPref('.openinnewtab');
  1230.   if (!bkmkNewTab)
  1231.     openUILink(url,event,false,true);
  1232.   else{
  1233.     if (event.shiftKey==true)
  1234.       openUILinkIn(url,"tabshifted");
  1235.     else
  1236.       openUILinkIn(url,"tab");
  1237.   }
  1238. }
  1239. function openInTabs(event){
  1240.   openBookmarksIn(event,"tab"+(event.shiftKey?"shifted":""));
  1241. }
  1242. function removeLabelFromBookmark(){
  1243.   var tree=document.popupNode;
  1244.   if (tree.tagName!="tree") tree = tree.parentNode;
  1245.   var visibleData=getTreeView(tree).data;
  1246.   var index=pops.getBookmarkIndex();
  1247.   var label=getTreeView(tree).getParentLabel(index);//visibleData[parent].fullTitle
  1248.   //dump("remove "+label+" label from bookmark\n");
  1249.   if(label!=null && label.length>0)
  1250.     GMS.removeLabelFromBookmark(visibleData[index],label,true);
  1251. }
  1252. function renameLabel(label, newLabel,refresh,event,children){
  1253.   var first=!label?true:false;
  1254.   if (!children) children=new Array();
  1255.   if (!label){
  1256.     var tree=document.popupNode;
  1257.     if (tree.tagName!="tree") tree = tree.parentNode;
  1258.     var visibleData=getTreeView(tree).data;
  1259.     label=visibleData[pops.getLabelIndex(event)];
  1260.   }
  1261.   newLabel = newLabel ? newLabel : prompt(strbundle.getString("renameLabel"),label.fullTitle);
  1262.   if (!newLabel || newLabel=="") return;
  1263.  
  1264.   var data=label.data;
  1265.  
  1266.   for (var i=0;i<data.length;i++){
  1267.     if (data[i].type==0){
  1268.       if (i==data.length-1 && refresh==null) refresh=true;
  1269.       renameLabel(data[i],newLabel+nestedChar+data[i].title,refresh==true,event,children);
  1270.     }
  1271.     else if (data[i].type==null){
  1272.       children.push({bkmk: data[i], oldlbl: label.fullTitle, newlbl: newLabel});
  1273.     }
  1274.   }
  1275.   if (refresh==null) refresh=true;
  1276.   GMS.onRenameLabel(label.fullTitle,newLabel,refresh==true);
  1277.   GMS.actionHist.pop();
  1278.   if (first){
  1279.     /* Create a bookmark action so it can be undone */
  1280.     GMS.generateBkmkAction("label","rename", children);
  1281.   }
  1282. }
  1283. function removeLabel(label, refresh,event,children,first){
  1284.   first=first==true||!label?true:false;
  1285.   if (!children) children=new Array();
  1286.   if (!label){
  1287.     var tree=document.popupNode;
  1288.     if (tree.tagName!="tree") tree = tree.parentNode;
  1289.     var visibleData=getTreeView(tree).data;
  1290.     label=visibleData[pops.getLabelIndex(event)];
  1291.     if (GMS.confirmDelete && !confirm(strbundle.getString("removeLabel")
  1292.         +" \""+label.fullTitle+"\"?"))
  1293.       return;
  1294.   }
  1295.  
  1296.   var data=label.data;
  1297.   var removed=false;
  1298.   for (var i=0;i<data.length;i++){
  1299.     if (data[i].type==0){
  1300.       if (i==data.length-1 && refresh==null) refresh=true;
  1301.       removeLabel(data[i],refresh==true);
  1302.     }
  1303.     else if (data[i].type==null){
  1304.       children.push({bkmk: data[i],label: label.fullTitle});
  1305.     }
  1306.   }
  1307.   if (refresh==null) refresh=true;
  1308.   GMS.onRemoveLabel(label.fullTitle,refresh,false);
  1309.   GMS.actionHist.pop()
  1310.   if (first){
  1311.     /* Create a bookmark action so it can be undone */
  1312.     GMS.generateBkmkAction("label","delete", children);
  1313.   }
  1314. }
  1315. function removeLabelAndBookmarks(label, refresh,event,children){
  1316.   if (!label){
  1317.     var tree=document.popupNode;
  1318.     if (tree.tagName!="tree") tree = tree.parentNode;
  1319.     var visibleData=getTreeView(tree).data;
  1320.     label=visibleData[pops.getLabelIndex(event)];
  1321.     if (GMS.confirmDelete && !confirm(strbundle.getString("removeLabel")
  1322.         +" \""+label.fullTitle+"\"?"))
  1323.       return;
  1324.   }
  1325.   var data=label.data;
  1326.   removeData(data,refresh,children, true);
  1327. }
  1328. function removeBookmarks(event){
  1329.   var tree=event.target.tagName=="tree"?event.target:document.popupNode.tagName=="tree"?document.popupNode:document.popupNode.parentNode;
  1330.   var view=getTreeView(tree);
  1331.   var selected=view.selectedData;
  1332.   var actionLength_Start=GMS.actionHist.length;
  1333.   var offset=0;
  1334.   for (var i=0;i<selected.length;i++){
  1335.     var sel=selected[i]+offset,startRows=view.rowCount;
  1336.     //dump("remove: "+view.data[sel].title+"\n");
  1337.     container=view.isContainer(sel);
  1338.     if (!container){
  1339.       GMS.onRemoveBookmark(view.data[sel],i==selected.length-1,i==0);
  1340.     }
  1341.     else{
  1342.       removeLabel(view.data[sel],i==selected.length-1?null:false,null,null,true);
  1343.     }
  1344.     offset+=view.rowCount-startRows;
  1345.   }
  1346.   var actionLength_End=GMS.actionHist.length;
  1347.   var actions=GMS.actionHist.slice(actionLength_Start,actionLength_End);
  1348.   GMS.generateBkmkAction("all","complex action",actions);
  1349.   view.selection.clearSelection();
  1350. }
  1351. function removeData(data,refresh,children,aIsFirst){
  1352.   if (!children) children=new Array();
  1353.   var first = aIsFirst || children.length==0;
  1354.   for (var i=0;i<data.length;i++){
  1355.     if (data[i].type==0){//Label
  1356.       if (i==data.length-1 && refresh==null) refresh=true;
  1357.       removeData(data[i].data,refresh==true,children);
  1358.     }
  1359.     else if (data[i].type==null){
  1360.       if (i==data.length-1){
  1361.         if (refresh==null) refresh=true;
  1362.       }
  1363.       else if (refresh==true) refresh=null;
  1364.       children.push(data[i]);
  1365.       GMS.onRemoveBookmark(data[i],refresh==true,false);
  1366.       GMS.actionHist.pop();
  1367.     }
  1368.   }
  1369.   if (first){
  1370.     /* Create a bookmark action so it can be undone */
  1371.     GMS.generateBkmkAction("label","deletebkmks", children);
  1372.   }
  1373. }
  1374. //Adds a label to a group of bookmarks via drag & drag
  1375. function addLabelFromDaD(bkmks, lbl,refresh,children){
  1376.   var first=refresh==null?true:false;
  1377.   if (!children) children=new Array();
  1378.   for (var i=0;i<bkmks.length;i++){
  1379.     if (bkmks[i].type==0){
  1380.       if (i==bkmks.length-1 && refresh==null) refresh=true;
  1381.       addLabelFromDaD(bkmks[i].data,lbl,refresh==true,children);
  1382.     }
  1383.     else{
  1384.       if (refresh==null) refresh=true;
  1385.       //dump("GMS.addLabel: "+lbl+" | "+bkmks[i].url+"\n");
  1386.       children.push(bkmks[i]);
  1387.       GMS.addLabelToBookmark(bkmks[i],lbl,i==bkmks.length-1 && refresh==true);
  1388.       GMS.actionHist.pop();/* Remove single history */
  1389.     }
  1390.   }
  1391.   if (first){
  1392.     /* Create a bookmark action so it can be undone */
  1393.     GMS.generateBkmkAction("label","add", children,lbl);
  1394.   }
  1395. }
  1396.  
  1397. var pops={
  1398.   getIndex: function(x,y,tree){
  1399.     var row = {}, col = {}, obj = {};
  1400.     tree.treeBoxObject.getCellAt(x, y, row, col, obj);
  1401.  
  1402.     return row.value;
  1403.   },
  1404.   getEventIndex:  function(event){
  1405.     return this.getIndex(event.clientX,event.clientY,event.target.parentNode);
  1406.   },
  1407.   getPopupIndex: function(id,event){
  1408.     var popup=document.getElementById(id);
  1409.     var x=popup.boxObject.x;
  1410.     var y=popup.boxObject.y;
  1411.  
  1412.     var tree=document.popupNode;
  1413.     if (tree.tagName!="tree") tree = tree.parentNode;
  1414.     var visibleData=getTreeView(tree).data;
  1415.  
  1416.     var index=this.getIndex(x,y,tree);
  1417.     if (index!=null && index>=0 && index<=visibleData.length)
  1418.       index=tree.currentIndex;
  1419.     else
  1420.       index=-1;
  1421.  
  1422.     return index;
  1423.   },
  1424.   getBookmarkIndex: function(event){
  1425.     return this.getPopupIndex("gm-contextPopup",event);
  1426.   },
  1427.   getLabelIndex: function(event){
  1428.     return this.getPopupIndex("gm-contextPopup",event);
  1429.   },
  1430.   getID: function(event){
  1431.     var tree=document.popupNode;
  1432.     if (tree.tagName!="tree") tree = tree.parentNode;
  1433.     var visibleData=getTreeView(tree).data;
  1434.     return visibleData[this.getBookmarkIndex(event)].id;
  1435.   },
  1436.   getURL: function(target){
  1437.     var tree=document.popupNode;
  1438.     if (tree.tagName!="tree") tree = tree.parentNode;
  1439.     ///dump("tree: "+target.tagName+" - "+tree.tagName+" - "+document.popupNode.tagName+"\n");
  1440.     var visibleData=getTreeView(tree).data;
  1441.     var idx=this.getBookmarkIndex();
  1442.     //dump("URL: " + visibleData[idx].url+" - "+idx+"\n");
  1443.     return visibleData[idx].url;
  1444.   },
  1445.   getLabels: function(event){//For bookmarks
  1446.     var tree=document.popupNode;
  1447.     if (tree.tagName!="tree") tree = tree.parentNode;
  1448.     var visibleData=getTreeView(tree).data;
  1449.     return visibleData[this.getBookmarkIndex(event)].url;
  1450.   },
  1451.   getNotes: function(event){
  1452.     var tree=document.popupNode;
  1453.     if (tree.tagName!="tree") tree = tree.parentNode;
  1454.     var visibleData=getTreeView(tree).data;
  1455.     return visibleData[this.getIBookmarkndex(event)].notes;
  1456.   },
  1457.   getBookmark: function(event){
  1458.     var tree=document.popupNode;
  1459.     if (tree.tagName!="tree") tree = tree.parentNode;
  1460.     var visibleData=getTreeView(tree).data;
  1461.     var vis=visibleData[pops.getBookmarkIndex()];
  1462.     var bm=GMS.createNewBookmark(vis.id,vis.url,vis.title,vis.labels,vis.notes);
  1463.     bm.mode=vis.mode;
  1464.     //dump("getBookmark: "+bm+"\n"+bm.url+'|'+bm.title+"|"+bm.id+"\n");
  1465.     return bm;
  1466.   },
  1467.  
  1468.   //For...lables....(the containers)...
  1469.   getLabel: function(event){
  1470.     var tree=document.popupNode;
  1471.     if (tree.tagName!="tree") tree = tree.parentNode;
  1472.     var visibleData=getTreeView(tree).data;
  1473.     var lbl=visibleData[this.getLabelIndex(event)].fullTitle;
  1474.     if (lbl==GMS.unlabeled) lbl="";
  1475.     return lbl;
  1476.   }
  1477. }
  1478.  
  1479. function doSearch(){
  1480.   var search=searchBox.value;
  1481.   if (search.length==0){
  1482.     //Normal view
  1483.     if (treeView){
  1484.       treeView.treeBox.beginUpdateBatch();
  1485.       if (treeView.type=="complete"){
  1486.         treeView.data=getVisibleData("complete",treeView);
  1487.       }
  1488.       else{
  1489.         treeView.data=getTreeData(treeView.parentLbl,true,treeView.type);
  1490.       }
  1491.       treeView.restoreContainers();
  1492.       treeView.treeBox.endUpdateBatch();
  1493.     }
  1494.   }
  1495.   else {
  1496.     treeView.saveOpened();
  1497.     GMS.getSiteSearch(search,"quickrefresh",true);
  1498.   }
  1499.  
  1500. }
  1501.  
  1502. function updateNotes(){
  1503.   if (searchBox.value.length==0)
  1504.     treeView.data=updateChildNotes(treeView.data);
  1505.   else{
  1506.     for (var i=0;i<GMS.searchArray.length;i++){
  1507.       treeView.data[i].notes=GMS.searchArray[i].notes;
  1508.       if (GMS.searchArray[i].notes.length>0){
  1509.         var bkmk=GMS.searchArray[i];
  1510.       }
  1511.     }
  1512.     treeView.treeBox.invalidate();
  1513.   }
  1514. }
  1515.  
  1516. function updateChildNotes(vData){
  1517.   for (var v=0;v<vData.length;v++){
  1518.     if (vData[v].type > 0 || vData[v].type==null){
  1519.       var index=GMS.isBookmarked(vData[v].url);
  1520.       vData[v].notes=GMS.bookmarkArray[index].notes;
  1521.     }
  1522.     else if (vData[v].type==0)
  1523.       vData[v].data=updateChildNotes(vData[v].data);
  1524.   }
  1525.   return vData;
  1526. }
  1527.  
  1528. function treeInit() {
  1529.   var tree = document.getElementById("gmarkList");
  1530.   if (tree){
  1531.     tree.setAttribute("hidden","false");
  1532.     treeView=new GMarksTreeView("complete");
  1533.     tree.view = treeView;
  1534.     tree.selType="single";
  1535.   }
  1536. }
  1537. function doSidebarUnload(){
  1538.   if (gmarksObserver!=null) gmarksObserver.unregister();
  1539.   if (treeView!=null)
  1540.     treeView.saveOpened();
  1541. }
  1542. function doOrganizeUnload(){
  1543.   if (gmarksObserver!=null) gmarksObserver.unregister();
  1544. }
  1545.  
  1546. function doSidebarLoad(){
  1547.   GMS=Components.classes["@mozilla.org/gmarks;1"]
  1548.     .getService(Components.interfaces.nsIGMarksService).wrappedJSObject;
  1549.   strbundle=document.getElementById("gmarksBundle");
  1550.   document.getElementById('addGMark').setAttribute('hidden',!prefs.getBoolPref('.showAddBookmark'));
  1551.  
  1552.   searchBox=document.getElementById('txtSearch');
  1553.   searchBox.focus();
  1554.   gmarksObserver=new GmarksObserverControl();
  1555.   //GMS.isSignedIn=GMS.checkSignedCookie();
  1556.   if (GMS.bookmarkArray.length>0)
  1557.     GM.onLoad();
  1558.   else if (!GMS.isSignedIn){
  1559.     var container=document.getElementById("signedOffContainer");
  1560.     container.setAttribute("hidden","false");
  1561.     var pass=GMS.getPassInfo();
  1562.     if (pass){
  1563.       document.getElementById("txtEmail").value=pass.user;
  1564.       document.getElementById("txtPassword").value=pass.password;
  1565.     }
  1566.     document.getElementById("autosignin").checked=prefs.getBoolPref(".signin");
  1567.     document.getElementById("gmarkList").setAttribute('hidden','true');
  1568.   }
  1569.   else{
  1570.     if (GMS.loading){
  1571.       document.getElementById("loadingContainer").setAttribute("hidden","false");
  1572.       if (treeView){
  1573.         treeView.treeBox.beginUpdateBatch();
  1574.         treeView.loading=true;
  1575.         treeView.treeBox.endUpdateBatch();
  1576.       }
  1577.     }
  1578.   }
  1579.   
  1580. }
  1581. function doOrganizeLoad(){
  1582.   GMS=Components.classes["@mozilla.org/gmarks;1"]
  1583.                      .getService(Components.interfaces.nsIGMarksService).wrappedJSObject;
  1584.   strbundle=document.getElementById("gmarksBundle");
  1585.   searchBox=document.getElementById('txtSearch');
  1586.   searchBox.focus();
  1587.   if (!gmarksObserver)
  1588.     gmarksObserver=new GmarksObserverControl();
  1589.   //dump("created organize observer\n");
  1590.   GMS.isSignedIn=GMS.checkSignedCookie();
  1591.   if (GMS.bookmarkArray.length>0){
  1592.     var treeLabels = document.getElementById("gmarkLabels");
  1593.     lblsTreeView=new GMarksTreeView("labels");
  1594.     treeLabels.view = lblsTreeView;
  1595.     treeLabels.selType="multiple";
  1596.     lblsTreeView.selection.select(0);
  1597.     var treeDetails = document.getElementById("gmarkDetails");
  1598.     if (lblsTreeView.data.length>0)
  1599.       treeView=new GMarksTreeView("details",lblsTreeView.data[0].fullTitle);
  1600.     else
  1601.       treeView=new GMarksTreeView("details","");
  1602.     treeDetails.view = treeView;
  1603.     treeView.openAll();
  1604.     treeDetails.selType="multiple";
  1605.     editField=document.getElementById("editableTxt");
  1606.     if (treeLabels.getAttribute("width")<100)
  1607.       treeLabels.setAttribute("height",100);
  1608.     document.getElementById("nameCol").setAttribute(
  1609.             "sortDirection","ascending");
  1610.     //dump("count: "+treeView.rowCount+"\n");
  1611.   }
  1612. }
  1613.  
  1614. function debug(msg){
  1615.   //var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
  1616.     //    .getService(Components.interfaces.nsIConsoleService);
  1617.     //consoleService.logStringMessage(msg);
  1618. }
  1619.